#include "Network/BanManager.h"
#include "Network/ServerRoot.h"
#include "Network/Client.h"

#include <fstream>
#include "Utils/Utils.h"
#include "GameSingleton.h"

namespace PocketSurvival
{
    BanManager::BanManager() {}
    BanManager::~BanManager() {}

    /**
     * @brief 封禁玩家
     * @param guid 玩家的 guid
    */
    void BanManager::addBanGuid(const GameGuid &guid)
    {
        m_banGuidSetMutex.lock();
        m_banGuidSet.insert(guid);
        m_banGuidSetMutex.unlock();

        ClientPtr client = GameSingleton::serverRoot->findClientByGuid(guid);
        if(client != nullptr)
        {
            client->disconnect("time out ...");
        }
    }

    /**
     * @brief 移除被封禁的玩家
     * @param guid 被封禁的玩家
     * @return true:解封成功，false:该玩家没有被封禁
    */
    bool BanManager::removeBanGuid(const GameGuid &guid)
    {
        std::lock_guard<SpinLock> lk(m_banGuidSetMutex);
        auto it = m_banGuidSet.find(guid);
        if(it != m_banGuidSet.end())
        {
            m_banGuidSet.erase(it);
            return false;
        }
        return false;
    }

    /**
     * @brief 判断玩家是否被封禁
     * @param guid 玩家的guid
     * @return true:该玩家是被封禁的，false:该玩家没在封禁列表里面
    */
    bool BanManager::guidIsInBanSet(const GameGuid &guid)
    {
        std::lock_guard<SpinLock> lk(m_banGuidSetMutex);
        return (m_banGuidSet.find(guid) != m_banGuidSet.end());
    }

    /**
     * @brief 封禁 IP
     * @param ipStr IP字符串，不要带端口，带端口的话基本等于无用
     * @note 封禁 IP 不会对在该 IP 下的客户端进行额外的封禁，但是会断开所有该 IP 的客户端
    */
    void BanManager::addBanIp(const std::string &ipStr)
    {
        m_banIpSetMutex.lock();
        m_banIpSet.insert(ipStr);
        m_banIpSetMutex.unlock();

        std::vector<ClientPtr> clientVec;
        GameSingleton::serverRoot->getAllClients(clientVec);
        for (ClientPtr &client : clientVec)
        {
            if (client->getAddress() == ipStr)
            {
                // ip 连带封禁功能
                // m_banGuidSetMutex.lock();
                // m_banGuidSet.insert(client->guid);
                // m_banGuidSetMutex.unlock();

                client->disconnect("time out ...");
            }
        }
    }
    
    /**
     * @brief 解除 IP 的封禁
     * @param ipStr IP字符串
     * @return true:解除成功，false:该IP没有被封禁
    */
    bool BanManager::removeBanIp(const std::string &ipStr)
    {
        std::lock_guard<SpinLock> lk(m_banIpSetMutex);
        auto it = m_banIpSet.find(ipStr);
        if(it != m_banIpSet.end())
        {
            m_banIpSet.erase(it);
            return false;
        }
        return false;
    }

    /**
     * @brief 判断 IP 是否是被封禁
     * @param ipStr IP字符串
     * @return true:该IP是被封禁的，false:IP没有被封禁
    */
    bool BanManager::ipIsInBanSet(const std::string &ipStr)
    {
        std::lock_guard<SpinLock> lk(m_banIpSetMutex);
        return (m_banIpSet.find(ipStr) != m_banIpSet.end());
    }

    /**
     * @brief 读取本地文件里面的封禁数据
     * @note 读取的时候会清理掉运行过程中的数据，然后再读取本地文件里面的封禁数据
    */
    void BanManager::load()
    {
        // 读取前先清空数据，防止数据重叠
        m_banGuidSet.clear();
        m_banIpSet.clear();

        std::ifstream stream;
        stream.open("./Server/ban.json");
        if(stream.is_open())
        {
            nlohmann::json jsonData;
            stream >> jsonData;

            for(auto &item : jsonData["BanGuid"])
            {
                m_banGuidSet.insert(item.get<GameGuid>());
            }
            for (auto &item : jsonData["BanIp"])
            {
                m_banIpSet.insert(item.get<std::string>());
            }
        }
        stream.close();
    }

    /**
     * @brief 将封禁的数据保存到本地文件 (Server/ban.json) 中
    */
    void BanManager::save()
    {
        nlohmann::json jsonData;
        // 理论上，下面的数据保存是不用加锁的
        jsonData["BanGuid"] = m_banGuidSet;
        jsonData["BanIp"] = m_banIpSet;

        Utils::SaveTextFile("./Server/ban.json", jsonData.dump());
    }

} // namespace PocketSurvival
